use regex::Regex;
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, process::Command};
mod fs_operator;

use fs_operator::{FnArgs, FsOperator, HanleRes};

// https://tauri.app/zh/v1/guides/features/command

#[tauri::command]
pub fn handle_ocr(file_src: &str) -> String {
    println!("{}", file_src);
    format!("OCR功能暂未实现: {}", file_src)

    // println!("{:?}", ocr_res);
    // match ocr_res {
    //     Ok(text) => text,
    //     Err(err) => format!("ocr error: {}", err.message())
    // }
}

// 返回的参数必须实现 Serialize 特征, 接受的参数必须实现 Serialize + Deserialize + Clone
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SearchParams {
    pub select_path: String,     // 指定目录
    pub input: String,           // 查询的字符串
    pub is_deep: bool,           // 是否递归查询
    pub is_reg: bool,            // 是否使用正则匹配
    pub search_type: SearchType, // 查询的类型
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum SearchType {
    ALL,
    FILE,
    DIR,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct FileInfo {
    pub path: PathBuf,
    pub is_dir: bool,
    pub is_file: bool,
}

impl FileInfo {
    pub fn new(path: PathBuf, is_dir: bool, is_file: bool) -> Self {
        FileInfo {
            path,
            is_dir,
            is_file,
        }
    }
}

/// 搜索操作
#[tauri::command]
pub fn search_path(invoke_params: SearchParams) -> Vec<FileInfo> {
    let SearchParams {
        select_path,
        input,
        is_deep,
        is_reg,
        search_type,
    } = invoke_params;

    let mut re: Option<Regex> = None;
    if is_reg {
        match Regex::new(&input) {
            Ok(regex) => re = Some(regex),
            Err(err) => {
                // 触发自定义事件, 提示报错信息
                let msg = format!("正则表达式无效, {}", err.to_string());
                println!("{}", msg);
                return vec![FileInfo::new(PathBuf::from(&msg), false, false)];
            }
        }
    };

    // 递归深度
    let max_depth = if is_deep { usize::MAX } else { 1 };

    // 查询本身
    let is_query_self = input == "";

    // 路径匹配统一处理闭包
    let path_handle = |e: FnArgs| -> Option<FnArgs> {
        let path = e.as_ref().unwrap().path().to_str().unwrap();

        // 查询本身, 则收集所有的文件
        if is_query_self {
            Some(e)
        } else {
            // 正则匹配
            if is_reg {
                if re.clone().unwrap().is_match(&path) {
                    Some(e)
                } else {
                    None
                }
            } else {
                // 普通匹配(不区分大小写)
                if path.contains(&input) {
                    Some(e)
                } else {
                    None
                }
            }
        }
    };

    // 文件过滤统一处理闭包
    let walk_dir_handle: Box<dyn Fn(FnArgs) -> Option<FnArgs>> = match search_type {
        SearchType::ALL => Box::new(|e| path_handle(e)),
        SearchType::DIR => {
            // 仅查询目录
            Box::new(|e| {
                if e.as_ref().unwrap().path().is_file() {
                    None
                } else {
                    path_handle(e)
                }
            })
        }
        SearchType::FILE => {
            // 仅查询文件
            Box::new(|e| {
                if e.as_ref().unwrap().path().is_dir() {
                    None
                } else {
                    path_handle(e)
                }
            })
        }
    };

    // 递归处理文件
    let path_list = FsOperator::walk_dir_read(&select_path, max_depth, walk_dir_handle).unwrap();

    // 获取迭代器
    let mut iter = path_list.into_iter();

    // 查询本身则跳过第一条数据(本身)
    if is_query_self {
        iter.next();
    }

    let mut result: Vec<_> = iter
        .map(|path| {
            let is_dir = path.is_dir();
            let is_file = path.is_file();
            FileInfo::new(path, is_dir, is_file)
        })
        .collect();

    // 去重
    result.dedup();

    result
}

/// 删除文件操作
#[tauri::command]
pub fn remove_files(invoke_params: Vec<String>) -> Vec<HanleRes> {
    FsOperator::rm_paths(invoke_params)
}

/// 重命名文件操作
#[tauri::command]
pub fn rename_files(invoke_params: Vec<(String, String)>) -> Vec<HanleRes> {
    FsOperator::remane_paths(invoke_params)
}

/// 重命名文件操作
#[tauri::command]
pub fn open_exe(file_src: &str) -> bool {
    println!("open_exe {}", file_src);

    // 使用 cmd /c 调用 oCam.exe
    let output = Command::new("cmd")
        .args(&["/c", "start", file_src])
        .output();

    match output {
        Ok(_) => println!("Executed successfully"),
        Err(e) => eprintln!("command.Run() failed with {}", e),
    }
    
    true
}
